9.6 複数エラーのラップ
複数エラーをラップするにはerrors.Join関数を使用する
code:go
package main
import (
"errors"
"fmt"
)
type Person struct {
FirstName string
LastName string
Age int
}
func ValidatePerson(p Person) error {
var errs []error
if len(p.FirstName) == 0 {
errs = append(errs, errors.New("field FirstName cannot be empty"))
}
if len(p.LastName) == 0 {
errs = append(errs, errors.New("field LastName cannot be empty"))
}
if p.Age < 0 {
errs = append(errs, errors.New("field Age cannot be negative"))
}
if len(errs) > 0 {
return errors.Join(errs...)
}
return nil
}
func main() {
err := ValidatePerson(Person{
FirstName: "",
LastName: "",
Age: -1,
})
fmt.Println(err)
// field FirstName cannot be empty
// field LastName cannot be empty
// field Age cannot be negative
}
複数ラップされたエラーをサポートするカスタムエラーを作成することができる
複数ラップされたエラー[]errorをerrors.Unwrap関数に渡すと必ずnilが返ってきてしまうので誤動作の原因になってしまう。その為、errors.Unwrap関数は直接使用すべきではない
複数ラップされたカスタムエラーや単一ラップされたカスタムエラーの処理をする場合、下記のように対応する
code:go
package main
import (
"errors"
"fmt"
)
type Status int
type StatusErr struct {
Status Status
Message string
}
func (se StatusErr) Error() string {
return se.Message
}
const (
InvalidLogin Status = iota + 1
NotFound
)
type MyError struct {
Code int
Errors []error
}
func (m MyError) Error() string {
return errors.Join(m.Errors...).Error()
}
func (m MyError) Unwrap() []error {
return m.Errors
}
func funcThatReturnsAnError() error {
return MyError{
Code: 12,
Errors: []error{
StatusErr{
Status: NotFound,
Message: "file Not Found",
},
errors.New("a simple string error"),
},
}
}
func main() {
var err error
err = funcThatReturnsAnError()
switch err := err.(type) {
case interface{ Unwrap() error }:
// 単一ラップエラー
innerErr := err.Unwrap()
fmt.Println(innerErr)
case interface{ Unwrap() []error }:
// 複数ラップエラー
innerErrs := err.Unwrap()
for _, innerErr := range innerErrs {
fmt.Println(innerErr)
// file Not Found
// a simple string error
}
default:
// デフォルト処理
}
}